//                 _              
//                | |             
//   __ _ _ __ ___| |__ __  _____ 
//  / _` | '__/ __| '_ \\ \/ / __|
// | (_| | | | (__| | | |>  <\__ \
//  \__,_|_|  \___|_| |_/_/\_\___/
//                                
// Copyright 2010 Scott Dixon http://www.archxs.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package com.archxs.commons;

import org.junit.Assert;
import org.junit.Test;

import com.archxs.commons.Variant;

/**
 * Unit-test coverage of the {@link java.lang.Number} base-class for Variants.
 */
public class VariantTestNumber {

    @Test 
    public void testGetNumbers() {
        final Variant numberTestFromInt = new Variant("255");
        Assert.assertEquals("255", numberTestFromInt.stringValue());
        Assert.assertEquals(255, numberTestFromInt.intValue());
        Assert.assertEquals(255, numberTestFromInt.longValue());
        Assert.assertEquals(255.0f, numberTestFromInt.floatValue(), 0.002);
        Assert.assertEquals(255.0d, numberTestFromInt.doubleValue(), 0.002);
        
        final Variant numberTestFromLong = new Variant("255l");
        Assert.assertEquals("255l", numberTestFromLong.stringValue());
        Assert.assertEquals(255, numberTestFromLong.intValue());
        Assert.assertEquals(255, numberTestFromLong.longValue());
        Assert.assertEquals(255.0f, numberTestFromLong.floatValue(), 0.002);
        Assert.assertEquals(255.0d, numberTestFromLong.doubleValue(), 0.002);
        
        final Variant numberTestFromHex = new Variant("0xFF");
        Assert.assertEquals("0xFF", numberTestFromHex.stringValue());
        Assert.assertEquals(255, numberTestFromHex.intValue());
        Assert.assertEquals(255, numberTestFromHex.longValue());
        Assert.assertEquals(255.0f, numberTestFromHex.floatValue(), 0.002);
        Assert.assertEquals(255.0d, numberTestFromHex.doubleValue(), 0.002);
        
        final Variant numberTestFromOctal = new Variant("0377");
        Assert.assertEquals("0377", numberTestFromOctal.stringValue());
        Assert.assertEquals(255, numberTestFromOctal.intValue());
        Assert.assertEquals(255, numberTestFromOctal.longValue());
        Assert.assertEquals(255.0f, numberTestFromOctal.floatValue(), 0.002);
        Assert.assertEquals(255.0d, numberTestFromOctal.doubleValue(), 0.002);
        
        final Variant numberTestFromFloat = new Variant("255.4f");
        Assert.assertEquals("255.4f", numberTestFromFloat.stringValue());
        Assert.assertEquals(255, numberTestFromFloat.intValue());
        Assert.assertEquals(255, numberTestFromFloat.longValue());
        Assert.assertEquals(255.4f, numberTestFromFloat.floatValue(), 0.002);
        Assert.assertEquals(255.4d, numberTestFromFloat.doubleValue(), 0.002);
        
        final Variant numberTestFromDouble = new Variant("255.5d");
        Assert.assertEquals("255.5d", numberTestFromDouble.stringValue());
        Assert.assertEquals(256, numberTestFromDouble.intValue());
        Assert.assertEquals(256, numberTestFromDouble.longValue());
        Assert.assertEquals(255.5f, numberTestFromDouble.floatValue(), 0.002);
        Assert.assertEquals(255.5d, numberTestFromDouble.doubleValue(), 0.002);
        
        final Variant numberTestFromConfusedDouble = new Variant("0255.5d");
        Assert.assertEquals("0255.5d", numberTestFromConfusedDouble.stringValue());
        Assert.assertEquals(256, numberTestFromConfusedDouble.intValue());
        Assert.assertEquals(256, numberTestFromConfusedDouble.longValue());
        Assert.assertEquals(255.5f, numberTestFromConfusedDouble.floatValue(), 0.002);
        Assert.assertEquals(255.5d, numberTestFromConfusedDouble.doubleValue(), 0.002);
        
        final Variant numberTestFromConfusedFloat = new Variant("0255.5f");
        Assert.assertEquals("0255.5f", numberTestFromConfusedFloat.stringValue());
        Assert.assertEquals(256, numberTestFromConfusedFloat.intValue());
        Assert.assertEquals(256, numberTestFromConfusedFloat.longValue());
        Assert.assertEquals(255.5f, numberTestFromConfusedFloat.floatValue(), 0.002);
        Assert.assertEquals(255.5d, numberTestFromConfusedFloat.doubleValue(), 0.002);
        
        final Variant numberTestFromConfusedDecimal = new Variant("0255.5");
        Assert.assertEquals("0255.5", numberTestFromConfusedDecimal.stringValue());
        Assert.assertEquals(256, numberTestFromConfusedDecimal.intValue());
        Assert.assertEquals(256, numberTestFromConfusedDecimal.longValue());
        Assert.assertEquals(255.5f, numberTestFromConfusedDecimal.floatValue(), 0.002);
        Assert.assertEquals(255.5d, numberTestFromConfusedDecimal.doubleValue(), 0.002);
        
        final Variant numberTestBadHex = new Variant("0xGG");
        Assert.assertEquals("0xGG", numberTestBadHex.stringValue());
        Assert.assertEquals(0, numberTestBadHex.intValue());
        Assert.assertEquals(0, numberTestBadHex.longValue());
        Assert.assertEquals(0.0f, numberTestBadHex.floatValue(), 0.002);
        Assert.assertEquals(0.0d, numberTestBadHex.doubleValue(), 0.002);
        
        final Variant numberTestBadOctal = new Variant("0GG");
        Assert.assertEquals("0GG", numberTestBadOctal.stringValue());
        Assert.assertEquals(0, numberTestBadOctal.intValue());
        Assert.assertEquals(0, numberTestBadOctal.longValue());
        Assert.assertEquals(0.0f, numberTestBadOctal.floatValue(), 0.002);
        Assert.assertEquals(0.0d, numberTestBadOctal.doubleValue(), 0.002);
        
        final String longMaxValue = String.format("0x%s",Long.toHexString(Long.MAX_VALUE));
        final Variant numberTestTooBigForInt = new Variant(longMaxValue);
        Assert.assertEquals(longMaxValue, numberTestTooBigForInt.stringValue());
        Assert.assertEquals(Integer.MAX_VALUE, numberTestTooBigForInt.intValue());
        Assert.assertEquals(Long.MAX_VALUE, numberTestTooBigForInt.longValue());
        Assert.assertTrue(numberTestTooBigForInt.floatValue() > 0);
        Assert.assertTrue(numberTestTooBigForInt.doubleValue() > 0);
        
        final String longMinValue = Long.toString(Long.MIN_VALUE);
        final Variant numberTestTooSmallForInt = new Variant(longMinValue);
        Assert.assertEquals(longMinValue, numberTestTooSmallForInt.stringValue());
        Assert.assertEquals(Integer.MIN_VALUE, numberTestTooSmallForInt.intValue());
        Assert.assertEquals(Long.MIN_VALUE, numberTestTooSmallForInt.longValue());
        Assert.assertTrue(numberTestTooSmallForInt.floatValue() < 0);
        Assert.assertTrue(numberTestTooSmallForInt.doubleValue() < 0);
    }
    
    @Test
    public void testInfiniteLoopCallstackBug() {
        final String troubleStringFloat = "[Ljava.lang.String;@5d3e754f";
        final String troubleStringLong = "[Ljava.lang.String;@5d3e754l";
        Assert.assertEquals(0f, Variant.valueOf(troubleStringFloat).floatValue(), 0.02f);
        Assert.assertEquals(0, Variant.valueOf(troubleStringFloat).doubleValue(), 0.02d);
        Assert.assertEquals(0, Variant.valueOf(troubleStringFloat).intValue());
        Assert.assertEquals(0l, Variant.valueOf(troubleStringFloat).longValue());
        
        Assert.assertEquals(0f, Variant.valueOf(troubleStringLong).floatValue(), 0.02f);
        Assert.assertEquals(0, Variant.valueOf(troubleStringLong).doubleValue(), 0.02d);
        Assert.assertEquals(0, Variant.valueOf(troubleStringLong).intValue());
        Assert.assertEquals(0l, Variant.valueOf(troubleStringLong).longValue());
    }
    
}
